﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace WebUtils
{
    /// <summary>
    /// 5.1.  Parameter Encoding
    /// </summary>
    /// <remarks> All parameter names and values are escaped using the [RFC3986] (Berners-Lee, T., “Uniform Resource Identifiers (URI): Generic Syntax,” .) percent-encoding (%xx) mechanism. Characters not in the unreserved character set ([RFC3986] (Berners-Lee, T., “Uniform Resource Identifiers (URI): Generic Syntax,” .) section 2.3) MUST be encoded. Characters in the unreserved character set MUST NOT be encoded. Hexadecimal characters in encodings MUST be upper case. Text names and values MUST be encoded as UTF-8 octets before percent-encoding them per [RFC3629] (Yergeau, F., “UTF-8, a transformation format of Unicode and ISO 10646,” .).<br>unreserved = ALPHA, DIGIT, '-', '.', '_', '~'</remarks>
    public static class ParameterEncoder
    {
        const string UNRESERVEDCHARS = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_.~";

        public static IEnumerable<EncodedURLParameter> EncodeParameters(this IEnumerable<UnEncodedURLParameter> pParameters)
        {
            return from param in pParameters select param.Encode();
        }

        public static IEnumerable<UnEncodedURLParameter> DecodeParameters(this IEnumerable<EncodedURLParameter> pParameters)
        {
            return from param in pParameters select param.Decode();
        }

        public static string ValueDecode(string pValue)
        {
            if (string.IsNullOrEmpty(pValue))
                return string.Empty;
            
            string result = pValue;
            int position = pValue.IndexOf('%');
            string fragment = null;
            char[] decodedChar = new char[1];

            while (position != -1)
            {
                fragment = result.Substring(position + 1, 2);
                decodedChar[0] = (char) (int.Parse(fragment, System.Globalization.NumberStyles.HexNumber));
                result = result.Replace('%' + fragment, new string(decodedChar));

                position = result.IndexOf('%');
            }

            return result;
        }

        /// <summary>
        /// This is a different Url Encode implementation since the default .NET one outputs the percent encoding in lower case.
        /// While this is not a problem with the percent encoding spec, it is used in upper case throughout OAuth
        /// </summary>
        /// <param name="value">The value to Url encode</param>
        /// <returns>Returns a Url encoded string</returns>
        public static string ValueEncode(string pValue)
        {
            if (string.IsNullOrEmpty(pValue))
                
                return string.Empty;

            StringBuilder result = new StringBuilder();

            foreach (char symbol in pValue)
            {
                if (UNRESERVEDCHARS.IndexOf(symbol) != -1)
                {
                    result.Append(symbol);
                }
                else
                {
                    result.Append('%' + String.Format("{0:X2}", (int)symbol));
                }
            }

            return result.ToString();
        }


    }
}
